﻿using System;

namespace Aeon.Emulator.Memory
{
    /// <summary>
    /// Describes a reserved block of conventional memory.
    /// </summary>
    [CLSCompliant(false)]
    public sealed class ReservedBlock : IEquatable<ReservedBlock>
    {
        #region Private Fields
        /// <summary>
        /// The segment address of the reserved block.
        /// </summary>
        private readonly ushort segment;
        /// <summary>
        /// The length of the reserved block in bytes.
        /// </summary>
        private readonly uint length;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the ReservedBlock class.
        /// </summary>
        /// <param name="segment">The segment address of the reseved block.</param>
        /// <param name="length">The length of the reserved block in bytes.</param>
        internal ReservedBlock(ushort segment, uint length)
        {
            this.segment = segment;
            this.length = length;
        }
        #endregion

        #region Operators
        /// <summary>
        /// Tests for equality between two blocks.
        /// </summary>
        /// <param name="blockA">First block.</param>
        /// <param name="blockB">Second block.</param>
        /// <returns>True if blocks are equal; otherwise false.</returns>
        public static bool operator ==(ReservedBlock blockA, ReservedBlock blockB)
        {
            if(object.ReferenceEquals(blockA, blockB))
                return true;

            if(object.ReferenceEquals(blockA, null))
                return false;

            return blockA.Equals(blockB);
        }
        /// <summary>
        /// Tests for inequality between two blocks.
        /// </summary>
        /// <param name="blockA">First block.</param>
        /// <param name="blockB">Second block.</param>
        /// <returns>True if blocks are not equal; otherwise false.</returns>
        public static bool operator !=(ReservedBlock blockA, ReservedBlock blockB)
        {
            if(object.ReferenceEquals(blockA, blockB))
                return false;

            if(object.ReferenceEquals(blockA, null))
                return true;

            return !blockA.Equals(blockB);
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the segment address of the reserved block.
        /// </summary>
        public ushort Segment
        {
            get { return this.segment; }
        }
        /// <summary>
        /// Gets the length of the reserved block in bytes.
        /// </summary>
        public uint Length
        {
            get { return this.length; }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Tests for value equality with another block.
        /// </summary>
        /// <param name="other">Other block to test.</param>
        /// <returns>True if blocks are equal; otherwise false.</returns>
        public bool Equals(ReservedBlock other)
        {
            if(object.ReferenceEquals(other, null))
                return false;

            return this.segment == other.segment && this.length == other.length;
        }
        /// <summary>
        /// Tests for value equality with another object.
        /// </summary>
        /// <param name="other">Other object to test.</param>
        /// <returns>True if objects are equal; otherwise false.</returns>
        public override bool Equals(object obj)
        {
            return Equals(obj as ReservedBlock);
        }
        /// <summary>
        /// Returns a hash code for the block.
        /// </summary>
        /// <returns>Hash code for the block.</returns>
        public override int GetHashCode()
        {
            return this.segment;
        }
        /// <summary>
        /// Returns a string representation of the block.
        /// </summary>
        /// <returns>String representation of the block.</returns>
        public override string ToString()
        {
            return string.Format("{0:X4}: {1}", this.segment, this.length);
        }
        #endregion
    }
}
